package yanivosher.aiproject;

import java.util.ArrayList;

public class GraphSearchState {

	public GraphSearchState selected = null;
	Graph graph;
	Step step;
	public GraphSearchState previous = null;
	Agent currentTurnAgent;
	public int stateDeep = 0;
	public int gameTurn = 0;

	public int stateValue = Integer.MIN_VALUE;
	public Pair twoPlayersVals;
	
	ArrayList<GraphSearchState> childStates = null;
	
	public GraphSearchState(GraphSearchState previous,Step step) {
		this.currentTurnAgent = previous.currentTurnAgent.opponent.deepCopy();
		this.currentTurnAgent.opponent = previous.currentTurnAgent.deepCopy();
		this.stateDeep = previous.stateDeep + 1;
		this.gameTurn = previous.gameTurn + 1;
		this.graph = makeStep(this.currentTurnAgent.opponent, step, previous.graph);
		this.previous = previous;
		this.step = step;
	}
	
	public GraphSearchState(Graph graph,Agent agent) {
		this.previous = null;
		this.graph = graph;
		this.gameTurn = Environment.gameTurn;
		this.currentTurnAgent = agent.deepCopy();
		this.currentTurnAgent.opponent = agent.getOpponent().deepCopy();
	}
	
	private Graph makeStep(Agent agent , Step step,Graph graph){
		
		Graph retGraph = graph.duplicateGraph();
		Vertex stepSrc = retGraph.getVertexById(step.current.getId());
		Vertex stepDest = retGraph.getVertexById(step.destination.getId());
		
		if (!step.getNoMove() ) {
			
			Edge e = retGraph.getEdgeBySourceDestination(stepSrc, stepDest);
			if(e == null)
			{
				Exception e1 = new Exception("Edge in Step cannot be null!!!");
				e1.printStackTrace();
			}
			int cost = e.getWeight();
			
			if (e.getIsBlocked() && step.chem && !step.military) {
				agent.raiseScore(Environment.getInstance().hellBreaksLooseCost);
			}
			if (e.getIsBlocked() && step.military && !step.chem) {
				retGraph.removeTerroristFromEdge(stepSrc,stepDest);
			}
			if (step.military) {
				stepSrc.setMilitary(stepSrc.getMilitary() - 1);
				stepDest.setMilitary(stepDest.getMilitary() + 1);
				cost *= 2;
			}
			if (step.chem) {
				stepSrc.setChem(stepSrc.getChem() - 1);
				stepDest.setChem(stepDest.getChem() + 1);
				cost *= 2;
			}
			//System.out.println("Moving from " + stepSrc.getId() + " to " + stepDest.getId());
			agent.currentVertex = stepDest;
			agent.raiseScore(cost);
		}
		else
		{
			agent.raiseScore(Environment.getInstance().noOpCost);
		}
		if (agent.currentVertex.equals(agent.destinationVertex) && retGraph.getVertexById(agent.currentVertex.getId()).getChem() > 0) {
			agent.chemsDestroyed += agent.currentVertex.getChem();
			retGraph.getVertexById(agent.currentVertex.getId()).setChem(0);
		}
		return retGraph;
	}
	
	public ArrayList<GraphSearchState> getChildStates() {
		ArrayList<GraphSearchState> retList = new ArrayList<GraphSearchState>();
		for (Edge edge : graph.getNeighborsEdges(graph.getVertexById(currentTurnAgent.currentVertex.getId()))) {
			retList.add(new GraphSearchState(this,new Step(edge.getDestination(),graph.getVertexById(currentTurnAgent.currentVertex.getId()),false,false)));
			if (graph.getVertexById(currentTurnAgent.currentVertex.getId()).getChem() > 0 && !edge.getIsBlocked()) {
				retList.add(new GraphSearchState(this,new Step(edge.getDestination(),graph.getVertexById(currentTurnAgent.currentVertex.getId()),true,false)));
			}
			if (graph.getVertexById(currentTurnAgent.currentVertex.getId()).getMilitary() > 0) {
				retList.add(new GraphSearchState(this,new Step(edge.getDestination(),graph.getVertexById(currentTurnAgent.currentVertex.getId()),false,true)));
			}
			if (graph.getVertexById(currentTurnAgent.currentVertex.getId()).getMilitary() > 0 && graph.getVertexById(currentTurnAgent.currentVertex.getId()).getChem() > 0) {
				retList.add(new GraphSearchState(this,new Step(edge.getDestination(),graph.getVertexById(currentTurnAgent.currentVertex.getId()),true,true)));
			}
		}
		retList.add(new GraphSearchState(this,new Step(graph.getVertexById(currentTurnAgent.currentVertex.getId()),graph.getVertexById(currentTurnAgent.currentVertex.getId()),false,false)));
		childStates = retList;
		return retList;
	}


	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		GraphSearchState other = (GraphSearchState) obj;
		if (graph == null) {
			if (other.graph != null)
				return false;
		} else if (!graph.equals(other.graph))
			return false;
		if (previous == null) {
			if (other.previous != null)
				return false;
		} else if (!previous.equals(other.previous))
			return false;
		if (step == null) {
			if (other.step != null)
				return false;
		} else if (!step.equals(other.step))
			return false;
		return true;
	}

	public boolean gameIsOver() {
		return graph.getChemVertexes().size() == 0 
				|| this.gameTurn >= Environment.T;
	}
	
	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		GraphSearchState state = this;
		while (state != null) {
			sb.append("Agent #" + state.currentTurnAgent.id + ":");
			sb.append(state.step);
			sb.append(" Minmax value: " + state.stateValue);
			sb.append(" stateDeep value: " + state.stateDeep);
			sb.append("\n");
			state = state.previous;
		}
		return sb.toString();
	}
}
